#include "BasicType/BasicTypeUtitlity.h"
#include "Math/BaseMath.h"

namespace GCRE {
	namespace BasicType {


		void StringUtitlity::SplitIntoTokens( const SFString& source, const SFString& seps, MFString& tokens )
		{
			tokens.clear();
			char *context = NULL;
			char *tempStr = new char[source.Length() + 1];
			strcpy_s( tempStr, source.Length() + 1, source.c_str() );
			char *token = strtok_s( tempStr, seps.c_str(), &context );
			while( NULL != token )
			{
				tokens.push_back( token );
				token = strtok_s( NULL, seps.c_str(), &context );
			}
			delete[] tempStr;
		}

		int StringUtitlity::CompareIgnoreCase( const SFString& src1, const SFString& src2 )
		{
			return _stricmp( src1.c_str(), src2.c_str() );
		}

		void StringUtitlity::SplitFullFileName( const SFString& fullfilename, SFString& path, SFString& filename, SFString& ext )
		{
			SFString temp;
			ReplaceCharacter( fullfilename, '/', '\\', temp );
			SFInt length = temp.Length();
			SFInt posDot = temp.rfind( '.' );
			ext = temp.substr( posDot + 1, length - posDot - 1 );
			SFInt posBacklash = temp.rfind( '\\' );
			path = temp.substr( 0, posBacklash );
			filename = temp.substr( posBacklash + 1, posDot - posBacklash - 1 );
		}

		void StringUtitlity::ReplaceCharacter( const SFString& source, SFChar s, SFChar t, SFString& result )
		{
			result = source;
			for ( int i = 0; i < result.Length(); i++ )
				if ( result[i] == s )
					result[i] = t;
		}

		Matrix44f MatrixUtitlity::Translation( const Vec3f& T )
		{
			Matrix44f result;
			result.row3 = _mm_set_ps( 1.0f, T[2], T[1], T[0] );
			return result;
		}

		Matrix44f MatrixUtitlity::Translation( SFFloat x, SFFloat y, SFFloat z )
		{
			Matrix44f result;
			result.row3 = _mm_set_ps( 1.0f, z, y, x );
			return result;
		}

		Matrix44f MatrixUtitlity::Scale( const Vec3f& S )
		{
			Matrix44f result;

			result.data[0][0] = S[0];
			result.data[1][1] = S[1];
			result.data[2][2] = S[2];

			return result;
		}

		Matrix44f MatrixUtitlity::Scale( SFFloat s )
		{
			Matrix44f result;

			result.data[0][0] = result.data[1][1] = result.data[2][2] = s;

			return result;
		}

		Matrix44f MatrixUtitlity::Scale( SFFloat sx, SFFloat sy, SFFloat sz )
		{
			Matrix44f result;

			result.data[0][0] = sx;
			result.data[1][1] = sy;
			result.data[2][2] = sz;

			return result;
		}

		Matrix44f MatrixUtitlity::RotationX( SFFloat rad )
		{
			Matrix44f result;

			result.data[1][1]= Math::cos( rad );
			result.data[1][2]=-Math::sin( rad );
			result.data[2][1]= Math::sin( rad );
			result.data[2][2]= Math::cos( rad );

			return result;
		}

		Matrix44f MatrixUtitlity::RotationY( SFFloat rad )
		{
			Matrix44f result;

			result.data[0][0]= Math::cos( rad );
			result.data[0][2]= Math::sin( rad );
			result.data[2][0]=-Math::sin( rad );
			result.data[2][2]= Math::cos( rad );

			return result;
		}

		Matrix44f MatrixUtitlity::RotationZ( SFFloat rad )
		{
			Matrix44f result;

			result.data[0][0]= Math::cos( rad );
			result.data[0][1]=-Math::sin( rad );
			result.data[1][0]= Math::sin( rad );
			result.data[1][1]= Math::cos( rad );

			return result;
		}

		Matrix44f MatrixUtitlity::RotationAxis( const Vec3f& R, SFFloat rad )
		{
			Matrix44f result;
			SFFloat x = R[0], y = R[1], z = R[2];
			SFFloat c = Math::cos( rad );
			SFFloat s = Math::sin( rad );
			SFFloat xx = x * x;
			SFFloat xy = x * y;
			SFFloat xz = x * z;
			SFFloat yy = y * y;
			SFFloat yz = y * z;
			SFFloat zz = z * z;

			result.row0 = _mm_set_ps( 0.0f, (1-c)*xz - y*s, (1-c)*xy + z*s, (1-c)*xx + c );
			result.row1 = _mm_set_ps( 0.0f, (1-c)*yz + x*s, (1-c)*yy + c, (1-c)*xy - z*s );
			result.row2 = _mm_set_ps( 0.0f, (1-c)*zz + c, (1-c)*yz - x*s, (1-c)*xz + y*s );

			return result;
		}

		const SFVec3f VectorUtitlity::XAxis( 1.0F, 0.0F, 0.0F );
		const SFVec3f VectorUtitlity::YAxis( 0.0F, 1.0F, 0.0F );
		const SFVec3f VectorUtitlity::ZAxis( 0.0F, 0.0F, 1.0F );

		SFVec3f VectorUtitlity::Cross( const SFVec3f& v1, const SFVec3f& v2 )
		{
			SFVec3f result;
			result[0] = v1[1] * v2[2] - v1[2] * v2[1];
			result[1] = v1[2] * v2[0] - v1[0] * v2[2];
			result[2] = v1[0] * v2[1] - v1[1] * v2[0];
			return result;
		}


		Quaternion QuaternionUtitlity::Slerp( SFFloat t, const Quaternion& q0, const Quaternion& q1 )
		{
			//	--TODO
			Quaternion result;
			return result;
		}

		Quaternion QuaternionUtitlity::SlerpExtraSpins( SFFloat t, const Quaternion& q0, const Quaternion& q1, SFInt k )
		{
			//	--TODO
			Quaternion result;
			return result;
		}

	}
}